﻿
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using miniLib.extensions;

namespace miniLib.Helpers
{


    /// <summary>
    /// 路径工具类
    /// </summary>
    public static class PathHelper
    {

        #region 属性
        /// <summary>
        /// 基础目录。GetFullPath依赖于此，默认为当前应用程序域基础目录
        /// </summary>
#if __CORE__
        public static string BaseDirectory { get; set; } = AppContext.BaseDirectory;
#else
        public static string BaseDirectory { get; set; } = AppDomain.CurrentDomain.BaseDirectory;
#endif

        /// <summary>
        /// 当前操作系统路径分隔符，兼容Windows和Linux
        /// </summary>
        public static char CurrentOsDirectorySeparator = Path.DirectorySeparatorChar;
        #endregion

  
        #region 路径操作辅助
        /// <summary>
        /// 获取绝对路径
        /// </summary>
        /// <param name="path"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        private static string GetPath(string path, int mode)
        {
            // 处理路径分隔符，兼容Windows和Linux
            var sep = CurrentOsDirectorySeparator;
            var sep2 = sep == '/' ? '\\' : '/';
            path = path.Replace(sep2, sep);
            var dir = "";
            switch (mode)
            {
                case 1:
                    dir = BaseDirectory;
                    break;
                case 2:
#if __CORE__
                    dir = AppContext.BaseDirectory;
#else
                    dir = AppDomain.CurrentDomain.BaseDirectory;
#endif
                    break;
#if !__CORE__
                case 3:
                    dir = Environment.CurrentDirectory;
                    break;
#endif
                default:
                    break;
            }
            if (dir.IsNullOrEmpty())
                return Path.GetFullPath(path);
            // 处理网络路径
            if (path.StartsWith(@"\\"))
                return Path.GetFullPath(path);
            if (!path.StartsWith(dir))
             {
                // path目录存在，不用再次拼接
                if (!Directory.Exists(path))
                {
                    path = path.TrimStart(sep);
                    path = Path.Combine(dir, path);
                }
            }
            
            return Path.GetFullPath(path);
        }

        /// <summary>
        /// 转换为当前操作系统的文件路径
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string ConvertToCurrentOsPath(string path)
        {
            var sep = CurrentOsDirectorySeparator == '/' ? '\\' : '/';
            return path.Replace(sep, CurrentOsDirectorySeparator);
        }

        /// <summary>
        /// 获取文件或目录的全路径，过滤相对目录
        /// </summary>
        /// <remarks>
        /// 不确保目录后面一定有分隔符，是否有分隔符由原始路径末尾决定
        /// </remarks>
        /// <param name="path">文件或目录</param>
        /// <returns></returns>
        public static string GetFullPath(this string path)
        {
            if (string.IsNullOrEmpty(path))
                return path;

            return GetPath(path, 1);
        }

        /// <summary>
        /// 获取文件或目录基于应用程序域基目录的全路径，过滤相对目录
        /// </summary>
        /// <remarks>
        /// 不确保目录后面一定有分隔符，是否有分隔符由原始路径末尾决定
        /// </remarks>
        /// <param name="path">文件或目录</param>
        /// <returns></returns>
        public static string GetBasePath(this string path)
        {
            if (string.IsNullOrEmpty(path))
                return path;

            return GetPath(path, 2);
        }

#if !__CORE__
        /// <summary>
        /// 获取文件或目录基于当前目录的全路径，过滤相对目录
        /// </summary>
        /// <remarks>
        /// 不确保目录后面一定有分隔符，是否有分隔符由原始路径末尾决定
        /// </remarks>
        /// <param name="path">文件或目录</param>
        /// <returns></returns>
        public static string GetCurrentPath(this string path)
        {
            if (string.IsNullOrEmpty(path))
                return path;

            return GetPath(path, 3);
        }
#endif

        /// <summary>
        /// 确保目录存在，若不存在则创建
        /// </summary>
        /// <remarks>
        /// 斜杠结尾的路径一定是目录，无视第二参数；
        /// 默认是文件，这样子只需要确保上一层目录存在即可，否则如果把文件当成了目录，目录的创建会导致文件无法创建。
        /// </remarks>
        /// <param name="path">文件路径或目录路径，斜杠结尾的路径一定是目录，无视第二参数</param>
        /// <param name="isfile">该路径是否是否文件路径。文件路径需要取目录部分</param>
        /// <returns></returns>
        public static string EnsureDirectory(this string path, bool isfile = true)
        {
            if (string.IsNullOrEmpty(path)) return path;
            path = path.GetFullPath();
            if (File.Exists(path) || Directory.Exists(path)) return path;
            var dir = path;
            // 斜杠结尾的路径一定是目录，无视第二参数
            if (dir[dir.Length - 1] == Path.DirectorySeparatorChar)
                dir = Path.GetDirectoryName(path);
            else if (isfile)
                dir = Path.GetDirectoryName(path);
            if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir);
            return path;
        }

        /// <summary>
        /// 合并多段路径
        /// </summary>
        /// <param name="path"></param>
        /// <param name="ps"></param>
        /// <returns></returns>
        public static string CombinePath(this string path, params string[] ps)
        {
            if (ps == null || ps.Length < 1)
                return path;
            if (path == null)
                path = string.Empty;
            foreach (var item in ps)
            {
                if (!item.IsNullOrEmpty())
                    path = Path.Combine(path, item);
            }
            return path;
        }
        #endregion

        #region 文件扩展
        /// <summary>
        /// 文件路径作为文件信息
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public static FileInfo AsFile(this string file) => new FileInfo(file.GetFullPath());

        /// <summary>
        /// 读取所有文本，自动检测编码
        /// </summary>
        /// <remarks>
        /// 性能较File.ReadAllText略慢，可通过提前检测BOM编码来优化
        /// </remarks>
        /// <param name="file"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string ReadText(this FileInfo file, Encoding encoding = null)
        {
            using (var fs = file.OpenRead())
            {
                if (encoding == null)
                    encoding = Encoding.UTF8;
                using (var reader = new StreamReader(fs, encoding))
                {
                    return reader.ReadToEnd();
                }
            }
        }

        /// <summary>
        /// 把文本写入文件，自动检测编码
        /// </summary>
        /// <param name="file"></param>
        /// <param name="text"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static FileInfo WriteText(this FileInfo file, string text, Encoding encoding = null)
        {
            using (var fs = file.OpenWrite())
            {
                if (encoding == null)
                    encoding = Encoding.UTF8;
                using (var writer = new StreamWriter(fs, encoding))
                {
                    writer.Write(text);
                }
            }
            return file;
        }

        /// <summary>
        /// 复制到目标文件，目标文件必须已存在，且源文件较新
        /// </summary>
        /// <param name="fi">源文件</param>
        /// <param name="destFileName">目标文件</param>
        /// <returns></returns>
        public static bool CopyToIfNewer(this FileInfo fi, string destFileName)
        {
            // 源文件必须存在
            if (fi == null || !fi.Exists)
                return false;
            var dest = destFileName.AsFile();
            // 目标文件必须存在且源文件较新
            if (dest.Exists && fi.LastWriteTime > dest.LastWriteTime)
            {
                fi.CopyTo(destFileName, true);
                return true;
            }
            return false;
        }
        #endregion

        #region 目录扩展
        /// <summary>
        /// 创建目录或者文件，当不存在时创建
        /// </summary>
        /// <param name="fullPath">全路径</param>
        /// <param name="isFile">是否文件，默认目录</param>
        /// <returns></returns>
        public static string CreateIfNotExists(this string fullPath, bool isFile = false)
        {
            if (!fullPath.IsNullOrEmpty())
            {
                if (!isFile)
                {
                    if (!Directory.Exists(fullPath))
                        Directory.CreateDirectory(fullPath);
                }
                else
                {
                    FileHelper.IsExist(fullPath);
                }
            }

            return fullPath;
        }

        /// <summary>
        /// 路径作为目录信息
        /// </summary>
        /// <param name="dir"></param>
        /// <returns></returns>
        public static DirectoryInfo AsDirectory(this string dir) => new DirectoryInfo(dir.GetFullPath());

        /// <summary>
        /// 获取目录内所有符合条件的文件，支持多文件扩展匹配
        /// </summary>
        /// <param name="di">目录</param>
        /// <param name="exts">文件扩展列表。比如*.exe;*.dll;*.config</param>
        /// <param name="allSub">是否包含所有子孙目录文件</param>
        /// <returns></returns>
        public static IEnumerable<FileInfo> GetAllFiles(this DirectoryInfo di, string exts = null, bool allSub = false)
        {
            if (di == null || !di.Exists)
                yield break;
            if (string.IsNullOrEmpty(exts))
                exts = "*";
            var opt = allSub ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
            foreach (var pattern in exts.Split(new char[] { ';', '|', ',' }))
            {
                foreach (var item in di.GetFiles(pattern, opt))
                {
                    yield return item;
                }
            }
        }

        #endregion

        public static string GetCurrentFullPath()=>Path.GetFullPath(Directory.GetCurrentDirectory());

        public  static string GetCurrentPath() =>Directory.GetCurrentDirectory();

        public static string GetFileExtName(string @this)=>Path.GetExtension(@this);

        public static string GetFileName(this string @this) => Path.GetFileName(@this);

        public static string GetTempFileName() => Path.GetTempFileName();

        public static IEnumerable<string> EnumerateFiles(string path, string searchPattern, SearchOption searchOption) => Directory.EnumerateFiles(path,searchPattern,searchOption);


        public static IEnumerable<string> EnumerateDirectories(string path, string searchPattern, SearchOption searchOption) => Directory.EnumerateDirectories(path, searchPattern, searchOption);
    }
}